﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Common.Logging;
using MonitorServer;
using Utility;

namespace MonitorClient
{
    public class MonitorTask : IDisposable
    {
        protected ILog log = LogFactory.CreateFileLog();
        IMessageQueue service;
        public MonitorTask()
        {
            service = MessageQueueService.CrateInstance();
        }
        public MonitorTask(IMessageQueue mqService)
        {
            if (mqService == null)
                service = MessageQueueService.CrateInstance();
            else
                service = mqService;
        }

        public string Name
        {
            get { return this.GetType().Name; }
        }
        public Config Config
        {
            get { return ConfigSetting.LoadConfig(); }
        }

        public Fiddler.FiddlerCoreStartupFlags Flag
        { 
            get
            {
                try
                {
                    Fiddler.FiddlerCoreStartupFlags flag =
                        (Fiddler.FiddlerCoreStartupFlags)Enum.Parse(typeof(Fiddler.FiddlerCoreStartupFlags), Config.StartupFlag);

                    return flag;
                }
                catch
                {
                    return Fiddler.FiddlerCoreStartupFlags.Default;
                }
            }
        }

        public void Start()
        {
            //Fiddler.FiddlerApplication.Log.OnLogString += new EventHandler<Fiddler.LogEventArgs>(Log_OnLogString);
            Fiddler.FiddlerApplication.BeforeRequest += new Fiddler.SessionStateHandler(FiddlerApplication_BeforeRequest);
            Fiddler.FiddlerApplication.BeforeResponse += new Fiddler.SessionStateHandler(FiddlerHostStatistical);
            Fiddler.FiddlerApplication.AfterSessionComplete += new Fiddler.SessionStateHandler(FiddlerApplication_AfterSessionComplete);

            //设置默认端口，见config.xml配置的ListenPort
            
            Fiddler.FiddlerApplication.Startup(Config.ListenPort, Flag);
            //Fiddler.FiddlerApplication.
        }

        public void FiddlerHostStatistical(Fiddler.Session oSession)
        {
            if (Config.Matched(oSession.url))
            {
                string id = oSession["id"];
                if (dic.ContainsKey(id))
                {
                    dic[id].ResponseTime = DateTime.Now;
                }
            }
        }

        private static Dictionary<string, SessionRecord> dic = new Dictionary<string, SessionRecord>();
        public void FiddlerApplication_BeforeRequest(Fiddler.Session oSession)
        {
            if (Config.Matched(oSession.url))
            {
                oSession["id"] = Guid.NewGuid().ToString();
                dic.Add(oSession["id"], new SessionRecord
                {
                    RequestTime = DateTime.Now,
                    URL = oSession.url
                });
            }
            //log.Info("BeforeRequest:"+oSession.url);
        }

/*
ClientConnected
ClientBeginRequest
GotRequestHeaders
ClientDoneRequest
Determine Gateway
DNS Lookup
TCP/IP Connect
HTTPS Handshake
ServerConnected
FiddlerBeginRequest
ServerGotRequest
ServerBeginResponse
GotResponseHeaders
ServerDoneResponse
ClientBeginResponse
ClientDoneResponse
*/
        public class SessionRecord
        {
            public DateTime RequestTime { get; set; }
            public DateTime? ResponseTime { get; set; }
            public string URL { get; set; }

            public int TimeSpan
            {
                get
                {
                    return ResponseTime.HasValue ? (ResponseTime.Value - RequestTime).Milliseconds : 0;
                }
            }
        }

        public void FiddlerApplication_AfterSessionComplete(Fiddler.Session oSession)
        {
            try
            {
                if (Config.Matched(oSession.url))
                {
                    string id = oSession["id"];
                    if (dic.ContainsKey(id) && dic[id].ResponseTime.HasValue)
                    {
                        //ToDo:
                        dic.Remove(id);
                    }
                    RequestEntity r = new RequestEntity()
                    {
                        ProcessId = oSession.LocalProcessID,
                        Url = oSession.url,
                        Location = Config.Location,
                        GatewayDeterminationTime = oSession.Timers.GatewayDeterminationTime,
                        DNSTime = oSession.Timers.DNSTime,
                        TCPConnectTime = oSession.Timers.TCPConnectTime,
                        ElapsedTime = oSession.Timers.ClientDoneResponse.Subtract(oSession.Timers.ClientBeginRequest).Milliseconds,
                        RequestTime = oSession.Timers.FiddlerBeginRequest,
                        HTTPSHandshake=oSession.Timers.HTTPSHandshakeTime,
                        ClientTime = oSession.Timers.ClientDoneRequest.Subtract(oSession.Timers.ClientConnected).Milliseconds
                          + oSession.Timers.ClientDoneResponse.Subtract(oSession.Timers.ClientBeginResponse).Milliseconds,
                        ServerTime = oSession.Timers.ServerDoneResponse.Subtract(oSession.Timers.ServerGotRequest).Milliseconds,
                        NetworkTime = oSession.Timers.ServerGotRequest.Subtract(oSession.Timers.ClientDoneRequest).Milliseconds
                          + oSession.Timers.ClientBeginResponse.Subtract(oSession.Timers.ServerBeginResponse).Milliseconds,

                        ClientConnected = oSession.Timers.ClientConnected,
                        ClientBeginRequest = oSession.Timers.ClientBeginRequest,
                        GotRequestHeaders=oSession.Timers.FiddlerGotRequestHeaders,
                        ClientDoneRequest = oSession.Timers.ClientDoneRequest,
                        ServerConnected = oSession.Timers.ServerConnected,
                        ServerGotRequest = oSession.Timers.ServerGotRequest,
                        ServerBeginResponse = oSession.Timers.ServerBeginResponse,
                        GotResponseHeaders=oSession.Timers.FiddlerGotResponseHeaders,
                        ServerDoneResponse = oSession.Timers.ServerDoneResponse,
                        ClientBeginResponse = oSession.Timers.ClientBeginResponse,
                        ClientDoneResponse = oSession.Timers.ClientDoneResponse
                    };
                    service.SendRequest(r);
                }
            }
            catch (Exception ex)
            {
                log.Error("Error:"+ex.Message, ex);
                Console.Write(ex.Message);
            }
        }

        public void Stop()
        {
            log.Info("WSFiddler Service Stoped.");
            //恢复监听之前的设置
            Fiddler.FiddlerApplication.Shutdown();
        }

        public void Dispose()
        {
            Stop();
        }
    }
}
